//
//  BKTree.cpp
//  NewBKTree
//
//  Created by Rune Juul Laugesen on 03/12/13.
//  Copyright (c) 2013 Rune Juul Laugesen. All rights reserved.
//

#include "BKTree.h"

BKTree::BKTree()
{
    _root = new BKTreeNode("");
    BuildAlphabet();
}

void BKTree::BuildAlphabet()
{
    _alphabet.insert ( pair<char, string>('.', ".") );
    _alphabet.insert ( pair<char, string>(',', ",") );
    _alphabet.insert ( pair<char, string>('!', "!") );
    _alphabet.insert ( pair<char, string>('?', "?") );
    _alphabet.insert ( pair<char, string>('a', "a  qsw") );
    _alphabet.insert ( pair<char, string>('b', " bhnv") );
    _alphabet.insert ( pair<char, string>('c', "  cfvx") );
    _alphabet.insert ( pair<char, string>('d', " defrs") );
    _alphabet.insert ( pair<char, string>('e', " de rsw") );
    _alphabet.insert ( pair<char, string>('f', "df grt") );
    _alphabet.insert ( pair<char, string>('g', " f ght y") );
    _alphabet.insert ( pair<char, string>('h', "   ghjuy") );
    _alphabet.insert ( pair<char, string>('i', " ijko u") );
    _alphabet.insert ( pair<char, string>('j', "hijku") );
    _alphabet.insert ( pair<char, string>('k', " ijklo") );
    _alphabet.insert ( pair<char, string>('l', "   klop") );
    _alphabet.insert ( pair<char, string>('m', "   klmn") );
    _alphabet.insert ( pair<char, string>('n', " bj mn") );
    _alphabet.insert ( pair<char, string>('o', " i klop") );
    _alphabet.insert ( pair<char, string>('p', "    lop") );
    _alphabet.insert ( pair<char, string>('q', "a q w") );
    _alphabet.insert ( pair<char, string>('r', " defrt") );
    _alphabet.insert ( pair<char, string>('s', "ade  sw") );
    _alphabet.insert ( pair<char, string>('t', "  fgrt y") );
    _alphabet.insert ( pair<char, string>('u', "hij   uy") );
    _alphabet.insert ( pair<char, string>('v', " bcgv") );
    _alphabet.insert ( pair<char, string>('w', "a eq sw") );
    _alphabet.insert ( pair<char, string>('x', "  cd xz") );
    _alphabet.insert ( pair<char, string>('y', "   ghtuy") );
    _alphabet.insert ( pair<char, string>('z', "    sxz") );
    _alphabet.insert ( pair<char, string>('0', "        90") );
    _alphabet.insert ( pair<char, string>('1', "12") );
    _alphabet.insert ( pair<char, string>('2', "123") );
    _alphabet.insert ( pair<char, string>('3', " 234") );
    _alphabet.insert ( pair<char, string>('4', "  345") );
    _alphabet.insert ( pair<char, string>('5', "   456") );
    _alphabet.insert ( pair<char, string>('6', "    567") );
    _alphabet.insert ( pair<char, string>('7', "     678") );
    _alphabet.insert ( pair<char, string>('8', "      789") );
    _alphabet.insert ( pair<char, string>('9', "       890") );
}

string BKTree::WordToKeys(string word)
{
    string keys = "";
    map<char, string>::iterator it;
    
    for (int i = 0; i < word.length(); i++)
    {
        it = _alphabet.find(tolower(word[i]));
        if (it == _alphabet.end())
        {
            keys += '1';
            continue;
        }
        keys += (*it).second;
    }
    return keys;
}

string BKTree::KeysToWord(string keys)
{
    string word = "";
    map<string, string>::iterator it;
    it = _dictionary.find(keys);
    if (it != _dictionary.end()) {
        word = (*it).second;
    }
    return word;
}

void BKTree::BuildDictionary(vector<string> trainingdata)
{
    for (auto it = trainingdata.begin(); it != trainingdata.end(); it++)
    {
        string word = (*it);
        string keys = WordToKeys(word);
        Insert(word);
        _dictionary.insert(pair<string, string>(keys,word));
    }
    
}

void BKTree::Insert(string word)
{
    if(word == "")
        cout << "Word can not be empty" << endl;
    
    BKTreeNode *newchild = new BKTreeNode(WordToKeys(word));
    
    if (_root->GetName() == "")
    {
        _root = newchild;
    }
    
    insertChild(_root, newchild);
}

void BKTree::insertChild(BKTreeNode *src, BKTreeNode *child)
{
    if (src->GetName() == child->GetName())
        return;
    
    int distance = LevenshteinDistance(src->GetName(), child->GetName());
    BKTreeNode *node = src->childAtDistance(distance);
    
    if (node->GetName() == "")
    {
        src->addChild(distance, child);
    }
    else
        insertChild(node, child);
}

map<int, string> BKTree::Search(string word, int maxdistance)
{
    map<int, string> words;
    map<int, string> keys = _root->Search(WordToKeys(word), maxdistance);
    for (auto it = keys.begin(); it != keys.end(); it++)
    {
        words.insert(pair<int, string>((*it).first, KeysToWord((*it).second)));
    }
    return words;
}

